#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>

#define P24 24
#define CONT 4
#define DEL() printf("\033[D \033[D")

/****************************************
* 从键盘输入，并把输入的值存入变量中
* str:  字符串变量
* n:    接收的长度
* show: '1' 显示， 其它不显示
*
*****************************************/
void cyscanf(char *str, int n, char show)
{
    int len = 0;
    char ch;
    struct termios old_term;
    struct termios cur_term;
    tcgetattr(STDIN_FILENO, &old_term);
    memcpy(&cur_term, &old_term, sizeof(cur_term));
    cur_term.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
    cur_term.c_cc[VMIN] = 1;
    cur_term.c_cc[VTIME] = 0;
    tcsetattr(STDIN_FILENO, TCSAFLUSH, &cur_term);

    while (1)
    {
        ch = getchar();
        if (ch == '\n') break;
        // 删除键特殊处理
        if (ch == 8 && len > 0)
        {
            // backspace
            len--;
            if(show) DEL();
            continue;
        }
        // 方向键处理
        if (ch == '\33')
        {
            ch = getchar();
            if (ch == '[')
            {
                ch = getchar();
                switch (ch)
                {
                    case 'A':
                        //printf("\nMOVEUP");
                        break;
                    case 'B':
                        //printf("\nMOVEDOWN");
                        break;
                    case 'C':
                        //printf("\nMOVERIGHT");
                        break;
                    case 'D':
                        //printf("\nMOVELEFT");
                        break;
                }
                continue;
            }
        }
        if (ch > 31 && ch <127 && len < n)
        {
            if(show == '1') printf("%c", ch);
            str[len++] = ch;
        }
        fflush(stdout);
    }
    tcsetattr(STDIN_FILENO, TCSAFLUSH, &old_term);
    str[len] = '\0';
    printf("\n");
}

// 返回两个自然数减乘除后得到所有结果
void getNums(int x, int y, int *r)
{
    int i,j;
    // 清空
    for(i = 0; i < 5; i++)
        r[i] = 0;

    // 加法
    i = 0;
    j = x + y;
    r[i] = j;
    i++;

    // 减法
    j = x - y;
    if(j > 0) {
        r[i] = j;
        i++;
    }
    j = y - x;
    if(j > 0) {
        r[i] = j;
        i++;
    }

    // 乘法
	j = x * y;
    r[i] = j;
    i++;

	// 除法
	if(x >= y)
	{
		if(y > 0) {
			j = x % y;
			if(j == 0) {
				r[i] = x / y;
				i++;
			}
		}		
	} else {
		if(x > 0) {
			j = y % x;
			if(j == 0) {
				r[i] = y / x;
				i++;
			}
		}
	}
}

// 判断x,y能否通过加减乘除变成z
int ok(int x, int y, int z)
{
    int i;
    if(x + y == z)
        return 1;
 
    if(x * y == z)
        return 1;

    if(x - y == z || y - x == z)
        return 1;

    if(y > 0) {
        i = x / y;
        if(y * i == x && i == z)
            return 1;
    }

    if(x > 0) {
        i = y / x;
        if(x * i == y && i == z)
            return 1;
    }

    return 0;
}

// 三个自然数能否通过加减乘除变成n
int ex(int x, int y, int z, int n)
{
    int i = 0;
    int r = 0;
    int p[5];
    getNums(x, n, p);
    while(p[i]) {
        r = ok(y, z, p[i]);
        if(r) {
            printf("%d,%d=%d vs %d eq %d\n", y, z, p[i], x, n);
            break;
        }
        i++;
    }
    if(r) return r;

    i = 0;
    getNums(y, n, p);
    while(p[i]) {
        r = ok(x, z, p[i]);
        if(r) {
            printf("%d,%d=%d vs %d eq %d\n", x, z, p[i], y, n);
            break;
        }
        i++;
    }
    if(r) return r;

    i = 0;
    getNums(z, n, p);
    while(p[i]) {
        r = ok(x, y, p[i]);
        if(r) {
            printf("%d,%d=%d vs %d eq %d\n", x, y, p[i], z, n);
            break;
        }
        i++;
    }

    return r;
}

void print24(int a, int b, int c, int d)
{
    int p[5];
    int i, j;

    // 拿其中一个数字，另外三个数字组成另一个数字，通过加减乘除，看看能否组成24点
    getNums(a, P24, p);
    i = 0;
    while(p[i]) {
        j = ex(b, c, d, p[i]);
        if(j) break;
        i++;
    }
    if(j){
        printf("ok\n");
        return;
    }
    getNums(b, P24, p);
    i = 0;
    while(p[i]) {
        j = ex(a, c, d, p[i]);
        if(j) break;
        i++;
    }
    if(j){
        printf("ok\n");
        return;
    }
    getNums(c, P24, p);
    i = 0;
    while(p[i]) {
        j = ex(b, a, d, p[i]);
        if(j) break;
        i++;
    }
    if(j){
        printf("ok\n");
        return;
    }
    getNums(d, P24, p);
    i = 0;
    while(p[i]) {
        j = ex(b, c, a, p[i]);
        if(j) break;
        i++;
    }
    if(j){
        printf("ok\n");
        return;
    }

    // 2个数组成一个数字，跟另外2个数字组成24点

    printf("%d %d %d %d 无法组成24点!\n", a, b, c, d);
}

int main(int argc, char *argv[])
{
    char cmd[50];
    int p[4];
    int i, j;

    printf("p24> 请输入命令:\n");
    while(1) {
        printf("p24> ");
        cyscanf(cmd,50,'1');
        if('q' == cmd[0] || 'Q' == cmd[0])
            break;

        for(i = 0; i < 4; i++)
            p[i] = 0;

        i = 0;
        j = 0;
        p[i] = 0;
        while(cmd[i] && j < 4) {
            // 通过ascii码判断是数字0-9
            if(cmd[i] >= 48 && cmd[i] <= 57) {
                p[j] = p[j] * 10 + cmd[i] - 48;
            } else {
                j++;
            }
            i++;
        }
        //printf("%d %d %d %d\n",p[0], p[1], p[2], p[3]);
        print24(p[0],p[1],p[2],p[3]);
    }

    return 0;
}
